#REM
	TimelineFX Module by Peter Rigby
	
	Web invaders example usage of TimelineFX
	
	Copyright (c) 2013 Peter J Rigby
	
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

#END

Import mojo
Import timelinefx
Import autofit

Global Seed = Millisecs()

Const UPDATE_RATE:Float = 60

#MOJO_AUTO_SUSPEND_ENABLED=False

'Create a basic App class
Class WebInvaders Extends App

	Field gamestate:GameState

	Method OnCreate()
		SetVirtualDisplay 640, 480
		
		gamestate = New GameState
		gamestate.LoadLevel()
		
		SetUpdateRate(UPDATE_RATE)
		SetUpdateFrequency(UPDATE_RATE)
	End
	
	'Use the OnUpdate method to update the particle manager
	Method OnUpdate()
		gamestate.Update()
	End
	
	'Use the OnRender method to render all particles
	Method OnRender()
		Cls(51, 51, 51)
		UpdateVirtualDisplay()
		gamestate.Render()
	End

End

Const DIAMOND:Int = 1
Const SQUARE:Int = 2
Const CIRCLE:Int = 3

Const REFLECT:Int = 1
Const ABSORB:Int = 2

'A basic game object class with a few bog standard fields, including a tlEffect 
'field so we can assign an effect to the object
Class GameObject
	Field gamestate:GameState
	Field effect:tlEffect
	
	Field speed:Float
	Field vector:tlVector2 = New tlVector2
	
	Field box:tlBox
	
End

'The Player class, used to set up and initialise the player
Class Player Extends GameObject

	Field bulletlist:List<Bullet>
	Field firerate:Float
	Field firecount:Float
	
	Method New(gamestate:GameState)
		Self.gamestate = gamestate
		'assign the player ship effect to the object from the effect library
		effect = CopyEffect(gamestate.effects.GetEffect("player ship"), Self.gamestate.pm)
		'set the objects initial position
		vector.SetPosition(50, VDeviceHeight() / 2)
		'tie the effect position to the vector that stores the object's position
		effect.TieToVector(vector)
		'add the player effect to the particle manager.
		Self.gamestate.pm.AddEffect(effect)
		bulletlist = New List<Bullet>
		firerate = 5 / UPDATE_RATE * 1000
		Print firerate
	End
	
	'update the player
	Method Update()
		If vector.y < MouseY()
			vector.Move(0, (VMouseY() -vector.y) / 20)
		ElseIf vector.y > VMouseY()
			vector.Move(0, (VMouseY() -vector.y) / 20)
		EndIf
		
		If MouseDown()
			firecount += firerate
			If firecount >= 1000
				firecount = 0
				Local b:Bullet = New Bullet(gamestate, Self)
				bulletlist.AddLast(b)
			End
		EndIf
		
		For Local b:Bullet = EachIn bulletlist
			b.Update
		Next
	End

End

'Bullet class to handle all the bullets fired from the player ship
Class Bullet Extends GameObject

	Field player:Player
	
	Method New(gamestate:GameState, player:Player)
		Self.gamestate = gamestate
		'assign Then Bullet effect to the object
		effect = CopyEffect(gamestate.effects.GetEffect("bullet 3"), Self.gamestate.pm)
		vector.SetPosition(player.vector.x + 25, player.vector.y)
		'tie the effect to the bullet position vector
		effect.TieToVector(vector)
		'change the angle of the effect so that it's aligned correctly
		effect.SetEffectAngle(90)
		speed = 1000 / UPDATE_RATE
		'add the effect to the particle manager
		Self.gamestate.pm.AddEffect(effect)
		Self.player = player
		'set up a collision box
		box = CreateBox(vector.x, vector.y, 40, 10)
	End
	
	Method Update()
		vector.Move(speed, 0)
		'if the bullet moves off the screen then remove it
		If vector.x > VDeviceWidth() +50
			effect.HardKill()
			player.bulletlist.Remove(Self)
		EndIf
		box.SetPosition(vector.x, vector.y)
		
	End

End

'the enemy class to handle all the ememies in the game
Class Enemy Extends GameObject
	
	Method New(gamestate:GameState)
		Self.gamestate = gamestate
		'assign the bullet effect from the effect library
		effect = CopyEffect(gamestate.effects.GetEffect("enemy1"), Self.gamestate.pm)
		vector.SetPosition(VDeviceWidth() +100, Rnd(VDeviceHeight()))
		'tie the effect to the enemy  position vector
		effect.TieToVector(vector)
		speed = (Rnd(100.0) + 75) / UPDATE_RATE
		Self.gamestate.pm.AddEffect(effect)
		'set up a collision box
		box = CreateBox(vector.x, vector.y, 20, 20)
	End

	
	Method Update:Void()
		vector.Move(-speed, Sin(vector.x))
		If vector.x < - 50
			'the enemy moves off the screen then remove it.
			effect.HardKill()
			gamestate.enemylist.Remove(Self)
			gamestate.enemycount -= 1
		EndIf
		box.SetPosition(vector.x, vector.y)
	End
End

'a gamestate class to manage the current state of the game each update
Class GameState
	
	Field effects:tlEffectsLibrary
	Field pm:tlParticleManager
	Field player:Player
	
	'Fields to store the background effects
	Field starfield:tlEffect
	Field lightning:tlEffect
	
	Field enemycount:Int
	Field maxenemies:Int
	Field enemylist:List<Enemy>
	
	Field background:Image
	
	Field dragging:Int
	
	Method New()
		effects = LoadEffects("effects")
		pm = CreateParticleManager(5000)
		'pm.DisableSetColor()
		
		player = New Player(Self)
		enemylist = New List<Enemy>
		
		'assign the background effects
		starfield = CopyEffect(effects.GetEffect("starfield"), pm)
		lightning = CopyEffect(effects.GetEffect("bgeffect"), pm)
		background = LoadImage("bg.jpg")
		
		'set the area sizes of the background effects
		starfield.SetAreaSize(VDeviceWidth(), VDeviceHeight())
		starfield.SetPosition(VDeviceWidth() / 2, VDeviceHeight() / 2)
		lightning.SetAreaSize(VDeviceWidth(), VDeviceHeight())
		lightning.SetPosition(VDeviceWidth() / 2, 0)
		
		'make sure the lightning effect does not timeout. If an effect hasn't spawned any particles for a while the particle manager will
		'remove it but we don't want that to happen for this effect.
		lightning.DoNotTimeOut(True)
		
		'Add the background effects to the particle manager
		pm.AddEffect(starfield)
		pm.AddEffect(lightning)
		
		'make sure the particle manager knows the current screen size.
		pm.SetScreenSize(VDeviceWidth(), VDeviceHeight())
		'set the origin of the particle manage to the top left of the screen
		pm.SetOrigin(VDeviceWidth() / 2, VDeviceHeight() / 2)
		
	End
	
	Method LoadLevel:Void()
		enemycount = 0
		maxenemies = 25
	End
	
	'update the enemies
	Method UpdateEnemies:Void()
		'spawn more if the number is less then the maxenemies allowed
		If enemycount < maxenemies
			Local e:Enemy = New Enemy(Self)
			enemylist.AddLast(e)
			enemycount += 1
		EndIf
		
		player.Update()
		
		'update each enemy and check for collisions with bullets
		For Local e:Enemy = EachIn enemylist
			e.Update()
			For Local b:Bullet = EachIn player.bulletlist
				Local result:tlCollisionResult = e.box.BoxCollide(b.box)
				If result.IsColliding()
					'kill the bullet and enemie effects if they collide
					b.effect.HardKill
					player.bulletlist.Remove(b)
					e.effect.HardKill
					enemylist.Remove(e)
					'grab an explosion effect and add it to the particle manager
					Local explosion:tlEffect = CopyEffect(effects.GetEffect("cloud blast 5"), pm)
					'position the explosion at the enemy position
					explosion.SetPositionVector(e.vector)
					pm.AddEffect(explosion)
					enemycount -= 1
				EndIf
			Next
		Next
	End
	
	Method Update:Void()
		UpdateEnemies()
		
		'update the particle manager	
		pm.Update()
	End

	Method Render:Void()
		DrawImage background, 0, - ( (background.Height - VDeviceHeight()) / 2)
		'Draw all the particles
		pm.DrawParticles()
	End
End

Function Main()
	
	New WebInvaders
	
End
